package com.example.sangong.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.example.sangong.config.MinioInfo;
import com.example.sangong.entity.Attachment;
import com.example.sangong.myenum.DeleteFlagEnum;
import io.minio.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Component
public class MinioUtils {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioInfo minioInfo;
    @Value("${minio.bucketName}")
    private String bucketName;
    @Value("${minio.accessServer}")
    private String accessServer;

    public String getAccessServer() {
        return accessServer;
    }

    /**
     * 上传文件
     *
     * @param files
     * @return
     * @throws Exception
     */
    public List<Attachment> batchUploadFile(List<MultipartFile> files) {
        if (CollectionUtil.isEmpty(files)) {
            return new ArrayList<>();
        }
        List<Attachment> result = new ArrayList<>();
        for (MultipartFile file : files) {
            result.add(uploadFile(file));
        }
        return result;
    }

    /**
     * 上传文件
     *
     * @param file
     * @return
     * @throws Exception
     */
    public Attachment uploadFile(MultipartFile file) {
        validateFileIsEmpty(file);
        try (InputStream inputStream = file.getInputStream()) {
            // 判断是否存在
            createBucket(bucketName);
            Attachment attachment = getAttachment(file);
            updateUploadFile(file, bucketName, inputStream, attachment);
            return attachment;
        } catch (Exception e) {
            log.error("上传失败：{}", e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    private void updateUploadFile(MultipartFile file, String bucketName, InputStream inputStream, Attachment attachment) {
        try {
            minioClient.putObject(PutObjectArgs.builder()
                    // 桶名称
                    .bucket(bucketName)
                    // 文件存储名称
                    .object(attachment.getNewName())
                    .stream(inputStream, file.getSize(), -1).contentType(file.getContentType()).build());
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

    }

    private static void validateFileIsEmpty(MultipartFile file) {
        if (null == file || 0 == file.getSize()) {
            log.error("msg{}", "上传文件不能为空");
            throw new RuntimeException("上传文件不能为空");
        }
    }

    private static Attachment getAttachment(MultipartFile file) {
        Attachment attachment = new Attachment();
        // 原文件名
        String originalFilename = file.getOriginalFilename();
        String suffix = FileUtil.getSuffix(originalFilename);
        long fileId = IdUtil.getSnowflake().nextId();
        String newFileName = fileId + "." + suffix;
        attachment.setId(IdUtil.getSnowflake().nextId());
        attachment.setNewName(newFileName);
        attachment.setOrginalName(originalFilename);
        attachment.setDeleteFlag(DeleteFlagEnum.EFFECTIVE.getCode());
        attachment.setFileType(suffix);
        attachment.setFileSize(file.getSize());
        attachment.setCreatedAt(LocalDateTime.now());
        attachment.setUpdatedAt(LocalDateTime.now());
        return attachment;
    }


    /**
     * 通过字节流上传
     *
     * @param imageFullPath
     * @param bucketName
     * @param imageData
     * @return
     */
    public String uploadImage(String imageFullPath, String bucketName, byte[] imageData) {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(imageData);
        try {
            // 判断是否存在
            createBucket(bucketName);
            minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(imageFullPath).stream(byteArrayInputStream, byteArrayInputStream.available(), -1).contentType(".jpg").build());
            return minioInfo.getEndpoint() + "/" + bucketName + "/" + imageFullPath;
        } catch (Exception e) {
            log.error("上传失败：{}", e.getMessage());
        }
        log.error("msg", "上传失败");
        return null;
    }

    /**
     * 删除文件
     *
     * @param bucketName
     * @param fileName
     * @return
     */
    public int removeFile(String bucketName, String fileName) {
        try {
            // 判断桶是否存在
            boolean res = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (res) {
                // 删除文件
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
            }
        } catch (Exception e) {
            System.out.println("删除文件失败");
            e.printStackTrace();
            return 1;
        }
        System.out.println("删除文件成功");
        return 0;
    }

    /**
     * 下载文件
     *
     * @param fileName
     * @param bucketName
     * @param response
     */
    public void fileDownload(String fileName, String bucketName, HttpServletResponse response) {

        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            if (StrUtil.isBlank(fileName)) {
                response.setHeader("Content-type", "text/html;charset=UTF-8");
                String data = "文件下载失败";
                OutputStream ps = response.getOutputStream();
                ps.write(data.getBytes("UTF-8"));
                return;
            }
            outputStream = response.getOutputStream();
            // 获取文件对象
            inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
            byte buf[] = new byte[1024];
            int length = 0;
            response.reset();
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName.substring(fileName.lastIndexOf("/") + 1), "UTF-8"));
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("UTF-8");
            // 输出文件
            while ((length = inputStream.read(buf)) > 0) {
                outputStream.write(buf, 0, length);
            }
            System.out.println("下载成功");
            inputStream.close();
        } catch (Throwable ex) {
            response.setHeader("Content-type", "text/html;charset=UTF-8");
            String data = "文件下载失败";
            try {
                OutputStream ps = response.getOutputStream();
                ps.write(data.getBytes("UTF-8"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        } finally {
            try {
                outputStream.close();
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 通过字节流下载
     *
     * @param fileName   文件名称
     * @param bucketName 桶名称
     * @return
     */
    public byte[] byteDownload(String fileName, String bucketName) {
        InputStream inputStream = null;
        try {
            inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
            byte[] buffer = StreamUtils.copyToByteArray(inputStream);
            inputStream.read(buffer);
            inputStream.close();
            return buffer;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    @SneakyThrows
    public void createBucket(String bucketName) {
        // 如果不存在就创建
        if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }
}